WebSocket 简介

一、WebSocket 协议出现背景

HTTP 协议的建立主要是传输 HTML 文档。但随着时代的发展,HTTP 协议的性能遇到了他的的瓶颈。即通信只能是客户端发起请求,这使得服务器有数据发生了变化客户端只有主动发起请求才能获得最新数据。

之后 comet 的出现实现了内容上的实时更新,但是 HTTP 本身的问题并未解决(通信只能客户端发起),于是出现了 WebSocket 协议。

comet 是一种服务器向页面推送数据的技术,实现方式有长轮询和 HTTP 流。

二、WebSocket 协议

1、概念

WebSocket 协议是 WEB 浏览器和 WEB 服务器全双工通信的标准。诞生于 2008 年,2011 年成为国际标准,目前支持的浏览器有 Firefox 6+、Safari 5+、Chrome、iOS 4+版Safari。

WebSocket 协议建立在 HTTP 协议基础之上,所以连接的发起方仍是客户端,一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。协议的标识符是ws,加密的是wss。

2、特点

  • 服务器向客户直接端推送数据。
  • 首部信息量小,通信量减少。
  • 没有同源的限制。

3、通信过程

WebSocket 通信需要在 HTTP 连接建立之后完成一次握手步骤。

客户端向服务器发送一个请求。需要用到 HTTP 的 Upgrade、Connection 首部字段,告知服务器通信协议发生改变。

1
2
3
4
5
6
7
8
9
10
11
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

# Sec-WebSocket-Key 字段内记录着握手过程中必不可少的键值。
# Sec-WebSocket-Protocol 字段内记录使用的子协议。子协议按 WebSocket 协议标准在连接分开使用时,定义那些连接的名称。

服务器收到请求后向客户端返回一个状态码 101 的响应。

1
2
3
4
5
6
7
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

# Sec-WebSocket-Accept 的字段值是由握手请求中的 Sec-WebSocket-Key 的字段值生成的。

成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数据帧,而采用 WebSocket 独立的数据帧。

4、WebSocket API

更多详情 https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

1)构造函数

WebSocket(url[, protocols]),返回一个 WebSocket 对象。

1
var ws = new WebSocket(url); // url 是绝对 url

实例化 WebSocket 对象后,浏览器就会马上尝试创建连接。

2)属性

  • readyState

与 XHR 类似,WebSocket 也有一个表示当前状态的 readyState 属性,但是的值与 XHR 并不相同。

1
2
3
4
CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

3)方法

  • send:对要传输的数据进行排队。(复杂的数据,在发送之前要进行序列化)
  • close:关闭当前链接。

4)事件

使用 addEventListener() 或将一个事件监听器赋值给本接口的 oneventname 属性监听下面的事件。

  • open:当一个 WebSocket 连接成功时触发。
  • close:当一个 WebSocket 连接被关闭时触发。
  • message:当通过 WebSocket 收到数据时触发。
  • error:当一个 WebSocket 连接因错误而关闭时触发,例如无法发送数据时。

三、实战

1、客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
const ws = new WebSocket("ws://localhost:8888");

ws.onopen = () => {
console.log('server open');
ws.send('hello world, server!');
};

ws.onmessage = (e) => {
console.log("client receive data:", e.data);
};

ws.onclose = (e) => {
console.log("server close");
};
</script>

2、服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const Koa = require('koa');
const WebSocket = require('ws');

const app = new Koa();
const ws = new WebSocket.Server({ port: 8888 });

ws.on('connection', ws => {
console.log('websocket connection');

ws.send('hello world, client!');

ws.on('open', msg => {
console.log('server open');
});

ws.on('message', msg => {
console.log('server receive msg:', msg);
});

ws.on('close', msg => {
console.log('client close',);
});
});

app.listen(3000, () => {
console.log(`Koa is listening in ${3000}`)
})
微信打赏